import Modal from "antd/lib/modal";
import "antd/lib/modal/style/css";
import Button from "antd/lib/button";
import "antd/lib/button/style/css";
import Col from "antd/lib/col";
import "antd/lib/col/style/css";
import Row from "antd/lib/row";
import "antd/lib/row/style/css";
import Divider from "antd/lib/divider";
import "antd/lib/divider/style/css";
import InputNumber from "antd/lib/input-number";
import "antd/lib/input-number/style/css";
// import Slider from "antd/lib/slider";
// import "antd/lib/slider/style/css";
import message from "antd/lib/message";
import "antd/lib/message/style/css";

import Switch from "antd/lib/switch";
import "antd/lib/switch/style/css";
import { ChromePicker } from "react-color";

import { PNG } from "brower-image-combiner";
import React, { ChangeEvent, Component, MouseEvent, ReactElement } from "react";
import { Editor } from "./editor";
import {
  SquareInfoExtractor,
  SquareInfo,
  SquareInfoInImage,
  SquareInfoAdapter,
  PreviewerCanvas,
} from "./previewer";
import JSZip from "jszip";
interface SquareEditorProps {
  visible?: boolean;
  source?: string;
  testWord?: string;
  testRender?: ReactElement;
  useDom?: boolean;
  onExport?: (target: Blob) => void;
  onClose?: () => void;
}
interface SquareEditorStates {
  src: string;
  scale: number;
  currentType: string;
  colorEditor: boolean;
  colorEditorState: any;
}

declare const version: string;

const WIDTH = 400;

const defaultState: SquareInfo & SquareEditorStates = {
  src: "",
  scale: 1,
  width: WIDTH,
  height: WIDTH * 0.7,
  left: 0,
  top: 0,
  right: 0,
  bottom: 0,
  currentType: "",
  offsetX: 0,
  offsetY: 0,
  scaleX: 0,
  scaleY: 0,
  fontSize: 12,
  color: "#000",
  pixelRatio: 1,
  vertical: false,
  colorEditor: false,
  colorEditorState: {} as any,
};
export default class Square extends Component<
  SquareEditorProps,
  SquareInfo & SquareEditorStates
> {
  state: SquareInfo & SquareEditorStates = JSON.parse(
    JSON.stringify(defaultState)
  );
  boxLeft = 0;
  boxTop = 0;
  colorEditEnd = false;
  fileName = "";
  target: HTMLDivElement | null = null;
  componentDidUpdate(prevProps: SquareEditorProps) {
    if (this.props.source !== prevProps.source) {
      if (this.props.source) {
        const src = this.props.source;
        this.handleImg(src);
      } else {
        this.setState(JSON.parse(JSON.stringify(defaultState)));
      }
    }
  }
  componentDidMount() {
    document.documentElement.addEventListener("dragover", (e) => {
      e.preventDefault();
    });
    document.documentElement.addEventListener("drop", (e) => {
      e.preventDefault();
      if (e.dataTransfer?.files?.length) {
        if (e.dataTransfer.files.length === 1) {
          //单文件输入
          const fileSource = e.dataTransfer.files[0];
          if (fileSource.name.endsWith("png")) {
            this.fileName = fileSource.name;
            const url = URL.createObjectURL(fileSource);
            this.handleImg(url);
          } else {
            message.error("导入文件格式不是PNG");
          }
        } else {
          if (!this.state.src) {
            message.error("请先选择一张图片作为模板");
          } else {
            const targets = Array.from(e.dataTransfer.files).filter((item) =>
              item.name.endsWith("png")
            );
            //多文件输入
            Modal.confirm({
              title: "提示",
              content: `检测到您传入了${targets.length}个图片，是否以当前图像为模板批量生效？`,
              okText: "确定",
              cancelText: "取消",
              onOk: () => {
                this.handleImgArray(targets);
              },
            });
          }
        }
      }
    });
  }
  componentWillUnmount() {}

  render() {
    return (
      <Modal
        transitionName=""
        visible={this.props.visible ?? true}
        onCancel={this.props.onClose}
        destroyOnClose
        footer={
          <div>
            <Button
              type={this.state.src ? "default" : "primary"}
              onClick={() => document.getElementById("file_input")!.click()}
            >
              上传原图
            </Button>
            <Button
              disabled={!this.state.src}
              onClick={() => document.getElementById("file_input2")!.click()}
            >
              选择模板
            </Button>
            <Button
              type="primary"
              disabled={!this.state.src}
              onClick={() => this.exportImage()}
            >
              完成
            </Button>
            <Button
              onClick={() => {
                this.props.onClose?.();
              }}
            >
              关闭
            </Button>
          </div>
        }
        style={{
          userSelect: "none",
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          cursor: ["left", "right"].includes(this.state.currentType)
            ? "col-resize"
            : !this.state.currentType
            ? "default"
            : "row-resize",
        }}
      >
        <input
          id="file_input"
          hidden
          type="file"
          accept="image/png"
          onChange={this.startEdit}
        />
        <input
          id="file_input2"
          hidden
          type="file"
          accept="image/png"
          onChange={this.selectTemplate}
        />
        <Row
          style={{
            width: this.state.vertical ? 602 : 402,
            overflowX: "hidden",
          }}
        >
          <Col span={this.state.vertical ? 18 : 24}>
            <h3>
              编辑九宫格
              <Switch
                style={{ marginLeft: 15 }}
                size="small"
                checkedChildren="竖排"
                unCheckedChildren="横排"
                checked={this.state.vertical}
                onChange={(e) => {
                  this.setState({ vertical: e });
                }}
              />
            </h3>
            <div
              style={{
                position: "relative",
                display: "inline-block",
                border: "1px solid #d9d9d9",
                width: this.state.width * this.state.scale + 2,
                height: this.state.height * this.state.scale + 2,
              }}
            >
              {this.state.src && (
                <Editor {...this.state} onMouseDown={this.onMouseDown} />
              )}
            </div>
            <Row style={{ marginTop: 10 }}>
              <Col span={6}>x偏移(px)</Col>
              <Col span={6}>y偏移(px)</Col>
              <Col span={6}>x收缩(px)</Col>
              <Col span={6}>y收缩(px)</Col>
            </Row>
            <Row>
              <Col span={6}>
                <InputNumber
                  precision={0}
                  min={-100}
                  max={100}
                  size="small"
                  value={this.state.offsetX}
                  onChange={(e) => {
                    this.setState({ offsetX: e });
                  }}
                />
              </Col>
              <Col span={6}>
                <InputNumber
                  precision={0}
                  min={-100}
                  max={100}
                  size="small"
                  value={this.state.offsetY}
                  onChange={(e) => {
                    this.setState({ offsetY: e });
                  }}
                />
              </Col>
              <Col span={6}>
                <InputNumber
                  precision={0}
                  min={-100}
                  max={100}
                  size="small"
                  value={this.state.scaleX}
                  onChange={(e) => {
                    this.setState({ scaleX: e });
                  }}
                />
              </Col>
              <Col span={6}>
                <InputNumber
                  precision={0}
                  min={-100}
                  max={100}
                  size="small"
                  value={this.state.scaleY}
                  onChange={(e) => {
                    this.setState({ scaleY: e });
                  }}
                />
              </Col>
            </Row>
            <Row style={{ marginTop: 15 }}>
              <Col span={6}>字号</Col>
              <Col span={6}>分辨率</Col>
              <Col span={6}>颜色</Col>
            </Row>
            <Row>
              <Col span={6}>
                <InputNumber
                  size="small"
                  min={6}
                  max={24}
                  onChange={this.changeFontSize}
                  value={this.state.fontSize}
                ></InputNumber>
              </Col>
              <Col span={6}>
                <InputNumber
                  size="small"
                  min={1}
                  max={3}
                  precision={1}
                  onChange={this.changePixelRatio}
                  value={this.state.pixelRatio}
                  formatter={(value) => `${value}x`}
                  parser={(value) => Number(`${value?.replace("x", "")}`)}
                ></InputNumber>
              </Col>
              <Col span={6}>
                <div
                  style={{
                    width: 25,
                    height: 25,
                    background: this.state.color,
                    borderRadius: 5,
                    position: "relative",
                    cursor: "pointer",
                    border: "1px solid #d9d9d9",
                  }}
                  onClick={(e) => {
                    this.colorEditEnd = false;
                    this.setState({
                      colorEditor: !this.state.colorEditor,
                      colorEditorState: { x: e.clientX, y: e.clientY },
                    });
                  }}
                >
                  {this.state.colorEditor && (
                    <>
                      <div
                        style={{
                          position: "fixed",
                          zIndex: 999,
                          left: 0,
                          top: 0,
                          height: "100vh",
                          width: "100vw",
                        }}
                        onClick={() => {
                          this.setState({
                            colorEditor: false,
                          });
                        }}
                      ></div>
                      <div
                        style={{
                          position: "fixed",
                          zIndex: 1000,
                          transform: "translate(-50%,-50%)",
                          left: this.state.colorEditorState.x,
                          top: this.state.colorEditorState.y,
                        }}
                        onClick={(e) => {
                          e.preventDefault();
                          e.stopPropagation();
                        }}
                      >
                        <ChromePicker
                          disableAlpha
                          color={this.state.color}
                          onChange={(e) => {
                            this.setState({ color: e.hex });
                          }}
                        ></ChromePicker>
                      </div>
                    </>
                  )}
                </div>
              </Col>
            </Row>
          </Col>
          <Col span={this.state.vertical ? 1 : 24}>
            <Divider
              type={this.state.vertical ? "vertical" : "horizontal"}
              style={
                this.state.vertical
                  ? {
                      height: "100%",
                    }
                  : {}
              }
            />
          </Col>
          <Col span={this.state.vertical ? 5 : 24}>
            <div style={{ marginBottom: 10, minHeight: 70 }}>
              <h3>预览</h3>
              <PreviewerCanvas
                {...this.state}
                text={this.props.testWord}
                render={this.props.testRender}
              />
            </div>
          </Col>
        </Row>
      </Modal>
    );
  }
  selectTemplate = (e: ChangeEvent<HTMLInputElement>) => {
    if (e.target.files?.[0]) {
      const source = e.target.files[0];
      const url = URL.createObjectURL(source);
      this.handleImgTemplate(url);
    }
  };
  startEdit = (e: ChangeEvent<HTMLInputElement>) => {
    if (e.target.files?.[0]) {
      const source = e.target.files[0];
      this.fileName = source.name;
      const url = URL.createObjectURL(source);
      this.handleImg(url);
    }
  };
  exportImage = (src = this.state.src, noDownload = false) => {
    return new Promise<Blob>((resolve) => {
      //prettier-ignore
      let {
      left,      right,       width,      top,         bottom,
      height,    offsetX,     offsetY,    scaleX,      scaleY,
      fontSize,  vertical,    color,      pixelRatio,
    } = this.state;
      right = width - right;
      bottom = height - bottom;
      //宽高记录在IHDR字段
      const data: Omit<SquareInfoInImage, "w" | "h"> = {
        L: Math.floor(left),
        R: Math.floor(right),
        T: Math.floor(top),
        B: Math.floor(bottom),
        OX: Math.floor(offsetX),
        OY: Math.floor(offsetY),
        SX: Math.floor(scaleX),
        SY: Math.floor(scaleY),
        F: Math.floor(fontSize),
        V: Number(vertical),
        v: version,
        c: color.replace("#", ""),
        p: pixelRatio,
      };
      const PNGCombiner = new PNG(this.state.width, this.state.height, {
        textInfo: `9PS${JSON.stringify(data)}9PE`,
      });
      const image = new Image();
      image.src = src;
      image.onload = () => {
        PNGCombiner.drawCanvas(image, width, height, 0, 0);
        // PNGCombiner.download();
        if (noDownload) {
          const file = PNGCombiner.getFile();
          resolve(file);
        } else {
          if (typeof this.props.onExport === "function") {
            const file = PNGCombiner.getFile();
            this.props.onExport(file);
          } else {
            PNGCombiner.download(this.fileName + ".9");
          }
        }
      };
    });
  };
  changeFontSize = (value: number) => {
    this.setState({ fontSize: value });
  };
  changePixelRatio = (value: number) => {
    this.setState({ pixelRatio: value });
  };
  onMouseDown = (e: MouseEvent<HTMLDivElement>) => {
    if (e.button === 0) {
      const div = e.target as HTMLDivElement;
      if (div.parentElement) {
        const { left, top } = div.parentElement.getBoundingClientRect();
        this.boxLeft = left;
        this.boxTop = top;
        this.target = div;
        this.setState({
          currentType: div.dataset.type || "",
        });
        document.addEventListener("mousemove", this.onMouseMove as any);
        document.addEventListener("mouseup", this.onMouseUp as any);
      }
    }
  };
  onMouseMove = (e: MouseEvent<HTMLDivElement>) => {
    const type = this.state.currentType;
    const x = Math.round(
      Math.min(
        this.state.width,
        Math.max(0, (e.clientX - this.boxLeft) / this.state.scale)
      )
    );
    const y = Math.round(
      Math.min(
        this.state.height,
        Math.max(0, (e.clientY - this.boxTop) / this.state.scale)
      )
    );
    const moveType = type.split("-");
    moveType.forEach((item: string) => {
      if (["left", "right"].includes(item)) {
        //@ts-ignore
        this.setState({
          [item]: x,
        });
      }
      if (["top", "bottom"].includes(item)) {
        //@ts-ignore
        this.setState({
          [item]: y,
        });
      }
    });
  };
  onMouseUp = (e: MouseEvent<HTMLDivElement>) => {
    if (e.button === 0) {
      this.setState({ currentType: "" });
      document.removeEventListener("mousemove", this.onMouseMove as any);
      document.removeEventListener("mouseup", this.onMouseUp as any);
    }
  };
  handleImgArray = async (files: File[]) => {
    const zip = new JSZip();
    for (let i = 0; i < files.length; i++) {
      const url = URL.createObjectURL(files[i]);
      const name = files[i].name;
      const data = await this.exportImage(url, true);
      zip.file(name + ".9.png", data);
    }
    const result = await zip.generateAsync({ type: "blob" });
    const url = URL.createObjectURL(result);
    const a = document.createElement("a");
    a.href = url;
    a.download =
      files.length + "images_9png_" + new Date().toLocaleString() + ".zip";
    a.click();
  };
  handleImgTemplate = (source: string) => {
    SquareInfoAdapter(SquareInfoExtractor(source)).then((data) => {
      const init = () => {
        this.setState({
          ...data,
          width: this.state.width,
          height: this.state.height,
        });
      };
      if (
        this.state.width !== data.width ||
        this.state.height !== data.height
      ) {
        Modal.confirm({
          title: "提示",
          content: "监测到模板的大小与当前图片不同，是否继续导入？",
          onOk: init,
          okText: "确定",
          cancelText: "取消",
        });
      } else {
        init();
      }
    });
  };
  handleImg = (source: string) => {
    const img = new Image();

    SquareInfoAdapter(SquareInfoExtractor(source))
      .then((data) => {
        img.onload = () => {
          this.setState({
            src: source,
            scale: WIDTH / Math.max(img.naturalWidth, img.naturalHeight),
            ...data,
          });
        };
        img.src = source;
      })
      .catch(() => {
        img.onload = () => {
          const nWidth = img.naturalWidth;
          const nHeight = img.naturalHeight;
          this.setState({
            src: source,
            width: img.naturalWidth,
            height: img.naturalHeight,
            scale: WIDTH / Math.max(img.naturalWidth, img.naturalHeight),
            left: Math.round(nWidth * 0.1),
            top: Math.round(nHeight * 0.1),
            right: Math.round(nWidth * 0.9),
            bottom: Math.round(nHeight * 0.9),
            scaleX: 0,
            scaleY: 0,
            vertical: false,
            offsetX: 0,
            offsetY: 0,
          });
        };
        img.src = source;
      });
  };
}
